package com.feng.study.demo.juc;

import java.util.concurrent.*;

public class JUCDemo03 {
    public static void main(String[] args) throws BrokenBarrierException, InterruptedException {

        BlockingQueue<String> queue = new LinkedBlockingDeque<>();

        // 三个多线程辅助类
        // 计数器
        // 工作线程之间彼此不关心
//        countDownLatchDemo();

        // 可以循环使用
        // 工作线程之间必须等到同一个点才能执行
        cyclicBarrierDemo();

        // 信号量，如：停车位数量有限
//        semaphoreDemo();

//        completableFutureDemo();
    }

    private static void completableFutureDemo() {
        CompletableFuture<String> completableFuture = new CompletableFuture<>();
    }

    /**
     * 信号量，如：停车位数量有限
     */
    private static void semaphoreDemo() throws InterruptedException {
        Semaphore semaphore = new Semaphore(3);
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                try {
                    //得到
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getId()+"抢到车位");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getId()+"离开车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    //释放
                    semaphore.release();
                }

            }).start();
        }
    }

    /**
     * CyclicBarrier利用ReentrantLock和Condition，
     * 自身维护了count和parties变量。
     * 每次调用await将count-1，
     * 并将线程加入到condition队列上。
     * 等到count为0时，则将condition队列的节点移交至AQS队列，并全部释放。
     */
    private static void cyclicBarrierDemo() {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(10,()->{
            System.out.println("所有子任务执行完成，开始执行主流程---");
        });
        for (int i = 0; i < 10; i++) {
            //成员变量的生命周期更长，当成员变量中饮用了局部变量，那么就需要加final，复制一份到堆内存中，否则引用的该变量就访问不到了
            //加final，变量会存在堆中的方法区里，子线程共享进程的堆，所以能读到。否则是存在另一个线程的栈中，不同线程读不到
//            final int finalI = i;
            //jdk1.8编译时自动加上final
            int finalI = i;
            new Thread(()->{
                System.out.println(Thread.currentThread().getId()+ ":"+ finalI);
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        //循环使用
        for (int i = 0; i < 10; i++) {
            final int finalI = i;
            new Thread(()->{
                System.out.println(Thread.currentThread().getId()+ ":"+finalI);
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

    /**
     * CountDownlatch基于AQS实现，
     * 会将构造CountDownLatch的入参传递至state，
     * countDown()就是在利用CAS将state减-1，
     * await()实际就是让头节点一直在等待state为0时，释放所有等待的线程
     */
    private static void countDownLatchDemo() throws InterruptedException {
        int size=10;
        CountDownLatch latch = new CountDownLatch(size);
        for (int i = 0; i < size; i++) {
            new Thread(()->{
                // 数量减一
                latch.countDown();
                System.out.println(Thread.currentThread().getId()+"剩余冰淇淋："+latch.getCount());
            }).start();
        }
        // CountDownLatch调用await()通常是主线程/调用线程
        latch.await();
        System.out.println("结束");
    }
}
